package com.mayisoftware.mayioa.business.flow.impl.serviceImpl;

import com.mayisoftware.mayioa.business.flow.api.domain.BaseFlowInfo;
import com.mayisoftware.mayioa.business.flow.api.service.IFlowBaseService;
import com.mayisoftware.mayioa.business.personal.api.domain.PersonalSign;
import com.mayisoftware.mayioa.business.personal.api.service.IPersonalSignService;
import com.mayisoftware.mayioa.business.plan.api.domain.PlanConfig;
import com.mayisoftware.mayioa.business.plan.api.service.IPlanConfigService;
import com.mayisoftware.mayioa.common.impl.utils.bean.ReflectionUtil;
import com.mayisoftware.mayioa.platform.api.domain.SysUser;
import com.mayisoftware.mayioa.platform.api.service.ISysUserService;
import com.mayisoftware.mayioa.platform.impl.util.ShiroUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricDetail;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 流程处理相关服务
 */
@Service
public class FlowBaseServiceImpl implements IFlowBaseService {

    /**
     * 日志类
     */
    private static final Logger log = LoggerFactory.getLogger(FlowBaseServiceImpl.class);
    /**
     * Flowable运行时服务
     */
    @Autowired
    private RuntimeService runtimeService;

    /**
     * Flowable任务相关服务
     */
    @Autowired
    private TaskService taskService;

    /**
     * Flowable仓库相关服务
     */
    @Autowired
    private RepositoryService repositoryService;

    /**
     * Flowable 流程处理引擎
     */
    @Autowired
    private ProcessEngine processEngine;

    /**
     * Flowable 历史记录信息
     */
    @Autowired
    private HistoryService historyService;

    /**
     * 用户报名服务
     */
    @Autowired
    private IPersonalSignService personalSignService;

    /**
     * 用户计划配置服务
     */
    @Autowired
    private IPlanConfigService planConfigService;
    /**
     * 用户服务
     */
    @Autowired
    private ISysUserService sysUserService;


    @Override
    public ProcessInstance createFlow(SysUser user,String planId,String signRemark) {

        PlanConfig planConfig =planConfigService.selectPlanConfigById(Long.parseLong(planId));
        BaseFlowInfo baseFlowInfo = new BaseFlowInfo();
        baseFlowInfo.setApplyUserId(user.getUserId().toString());
        baseFlowInfo.setApplyUserName(user.getUserName().toString());
        baseFlowInfo.setPlanName(planConfig.getPlanCfgName());
        baseFlowInfo.setPlanId(planId);
        baseFlowInfo.setRemark("提交报名信息");
        if (StringUtils.isEmpty(signRemark)){
            baseFlowInfo.setSignRemark("无");
        }
        else {
            baseFlowInfo.setSignRemark(signRemark);
        }


        // 根据计划查询流程ID
        PlanConfig config = planConfigService.selectPlanConfigById(Long.parseLong(planId));
        String processName = config.getPlanCfgFlowId();

        ProcessEngineConfiguration peConfig= processEngine.getProcessEngineConfiguration();

        HashMap<String, Object> map = new HashMap<>();
        Field[] fields= ReflectionUtil.getAllDeclareFields(BaseFlowInfo.class);

        for (Field field:fields){
            map.put(field.getName(),ReflectionUtil.getFieldValue(baseFlowInfo,field.getName()));
        }

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processName, map);

        return processInstance;
    }

    @Override
    public List<Task> queryTasks(String userId, String userList,List<String> groupIds) {
        List<Task> res = new ArrayList<>();
        if (!StringUtils.isEmpty(userId)){
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
            res.addAll(tasks);
        }

        if (!StringUtils.isEmpty(userList)){
            List<Task> tasks = taskService.createTaskQuery().taskCandidateUser(userList).orderByTaskCreateTime().desc().list();
            res.addAll(tasks);
        }

        if (!CollectionUtils.isEmpty(groupIds)){
            List<Task> tasks = taskService.createTaskQuery().taskCandidateGroupIn(groupIds).orderByTaskCreateTime().desc().list();
            res.addAll(tasks);
        }
        return res;
    }

    @Override
    public boolean apply(String taskId,String remark) {

        return  setAndCompleteTask(taskId,remark,"通过");
    }

    private boolean  setAndCompleteTask(String taskId,String remark,String outcome){
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return false;
        }
        String processId = task.getProcessInstanceId();

        PersonalSign personalSign = new PersonalSign();
        personalSign.setProcessId(processId);
        List<PersonalSign> personalSigns = personalSignService.queryApplyInfo(personalSign);

        if (CollectionUtils.isEmpty(personalSigns)){
            return false;
        }
        PersonalSign sign = personalSigns.get(0);

        BaseFlowInfo baseFlowInfo = new BaseFlowInfo();
        PlanConfig config= planConfigService.selectPlanConfigById(sign.getPerSignPlanId().longValue());
        baseFlowInfo.setPlanName(config.getPlanCfgName());
        baseFlowInfo.setFlowName( task.getName());
        baseFlowInfo.setRemark(remark);
        baseFlowInfo.setPlanId(sign.getPerSignPlanId().toString());
        baseFlowInfo.setOutcome(outcome);

        baseFlowInfo.setApplyUserId(sign.getPerSignUserId().toString());
        SysUser user =sysUserService.selectUserById(sign.getPerSignUserId().longValue());
        baseFlowInfo.setApplyUserName(user.getUserName());

        SysUser loginUser=ShiroUtils.getSysUser();
        baseFlowInfo.setApprovalUserId(loginUser.getUserId().toString());
        baseFlowInfo.setApprovalUserName(loginUser.getUserName());

        //通过审核
        HashMap<String, Object> map = new HashMap<>();

        Field[] fields = ReflectionUtil.getAllDeclareFields(BaseFlowInfo.class);

        for (Field field:fields){
            map.put(field.getName(),ReflectionUtil.getFieldValue(baseFlowInfo,field.getName()));
        }

        for (Field field:fields){
            map.put(task.getTaskDefinitionKey()+"|"+field.getName(),ReflectionUtil.getFieldValue(baseFlowInfo,field.getName()));
        }

        taskService.complete(taskId, map);
        return  true;
    }

    @Override
    public boolean reject(String taskId,String remark) {
        return  setAndCompleteTask(taskId,remark,"驳回");
    }

    /**
     * 流程是否已经结束
     *
     * @param processInstanceId 流程实例ID
     * @return
     */
    @Override
    public boolean isFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished()
                .processInstanceId(processInstanceId).count() > 0;
    }

    /**
     * 查询历史流程信息
     */
    @Override
    public HistoricProcessInstance queryProcessInfo(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
    }

    /**
     * 查询历史流程任务信息
     */
    @Override
    public List<HistoricTaskInstance> queryProcessTaskInfos(String processId){
        List<HistoricTaskInstance> historicTaskInstances= historyService.createHistoricTaskInstanceQuery().processInstanceId(processId).orderByHistoricTaskInstanceStartTime()
                .asc().list();
        List<HistoricDetail> details= historyService.createHistoricDetailQuery().processInstanceId(processId).list();

        List<HistoricActivityInstance> actis= historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).list();
        return historicTaskInstances;
    }

    /**
     * 查询历史流程节点信息
     */
    @Override
    public List<HistoricActivityInstance> queryProcessActivityInfos(String processId){

        List<HistoricActivityInstance> actis= historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
        return actis;
    }


    @Override
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) {

        /**
         * 获得当前活动的节点
         */
        String processDefinitionId = "";
        if (this.isFinished(processId)) {// 如果流程已经结束，则得到结束节点
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();

            processDefinitionId=pi.getProcessDefinitionId();
        } else {// 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId=pi.getProcessDefinitionId();
        }
        List<String> highLightedActivitis = new ArrayList<String>();

        /**
         * 获得活动的线
         */
        List<HistoricActivityInstance> highLightedActivitList =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();

        for(HistoricActivityInstance tempActivity : highLightedActivitList){
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivitis, flows, engconf.getActivityFontName(),
                engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } catch (IOException e) {
            log.error("操作异常",e);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
        }
    }

    /**
     * 查询历史流程的变量信息
     */
    @Override
    public List<HistoricVariableInstance> queryProcessVariableInfos(String processId){

         List<HistoricVariableInstance> res = processEngine.getHistoryService().createHistoricVariableInstanceQuery()
                 .processInstanceId(processId).list();
         return res;
    }
}
